JS Notes 2
Javascript: Class Inheritance, promise and callback
Class
Class Inheritance, static properties and methods.
Helpful Link: javascript.info
Class inheritance in js inherits protoype methods and properties from parents, unless child's property have the same key.
class Animal{
constructor(name, weight){
this.name = name;
this.speed = 0;
}
run(speed){
this.speed = speed;
console.log(`Running at speed of ${speed}`);
}
}
class Rabbit extends Animal{
constructor(name, ...args){
// Derived constructor must call super to init the creation and assignment of object and this.
// A default constructor will be defined automatically if derived constructor is not defined.
super(name);
[this.color, this.weight] = args;
}
hide(){
console.log(`${this.color} ${this.name} can hide, weights: ${this.weight}`);
}
}
let rabbit = new Rabbit("Rabbit", "White", 123);
rabbit.run(100);
rabbit.hide();
[[HomeObject]] and super
Summary
super.method()can't be implemented usingthis.__proto__.method.call(this).- That works in simple cases but breaks in inheritance chains, because this always refers to the current object, not the method’s home object.
- The result: infinite recursion when trying to go further up the chain.
Solution is to use [[HomeObject]], this hidden property remebers the method was created in which allows super to find the correct parent avoiding recursion.
Extended clock example question from javascript.info
class Clock {
constructor({ template }) {
this.template = template;
console.log(this.template);
}
render() {
let date = new Date();
let hours = date.getHours();
if (hours < 10) hours = '0' + hours;
let mins = date.getMinutes();
if (mins < 10) mins = '0' + mins;
let secs = date.getSeconds();
if (secs < 10) secs = '0' + secs;
let output = this.template
.replace('h', hours)
.replace('m', mins)
.replace('s', secs);
console.log(output);
}
stop() {
clearInterval(this.timer);
}
start() {
this.render();
this.timer = setInterval(() => this.render(), 1000);
}
}
class ExtendedClock extends Clock{
constructor(options){
super(options);
const {precision = 1000} = options;
this.precision = precision;
}
start() {
this.render();
this.timer = setInterval(() => this.render(), this.precision);
}
}
let a = new ExtendedClock({template: "h-m-s"});
a.start();
setTimeout(() => a.stop(), 5000);
Static property and methods
Static methods belongs to the class, shared for all instances. You can access using the class name not object.
class Test{
static name = "class name"
}
let a = new Test();
console.log(Test.name); // -> class name
console.log(a.name) // -> undefined
Inherit static methods
class Person{
static name = "class name"
constructor(){
}
}
class Student extends Person{
static cmp_gpa(student_a, student_b){
return student_a.gpa > student_b.gpa;
}
constructor(gpa){
super();
this.gpa = gpa;
}
}
let a = new Student(2.12);
let b = new Student(3.12);
console.log(`Student A has ${Student.cmp_gpa(a, b) ? "higher" : "lower"} GPA than student B.`);
Public, private, protected
Public - default
Protected properties - starts with underscore _, not enforced on language level just convention like in python. Use getter/setter with these properties. Is inherited.
read only - this._name would make property only changable during creation.
Private - #private_var, only accessable within can't be inherted. Doesn't conflict with public properties.
class Product {
#serial; // private field
constructor(name, price) {
this.name = name;
this.price = price; // go through the setter for validation
this.#serial = Math.floor(Math.random() * 1e8); // auto-generate serial
}
// getter and setter for price
get price() {
return this._price;
}
set price(newPrice) {
if (typeof newPrice !== "number" || newPrice < 0) {
throw new Error("Price must be a non-negative number.");
}
this._price = newPrice;
}
// getter for serial (read-only: no setter)
get serial() {
return this.#serial;
}
// a method for product info
info() {
return `Product: ${this.name}, Price: $${this.price}, Serial: ${this.serial}`;
}
}
// Example usage:
let a = new Product("My Product", 123);
console.log(a.info()); // ✅ shows product details
a.price = 200; // ✅ updates price safely
console.log(a.info());
console.log(a.serial);
Extending built-in classes
Promises, async/await
Callback
A callback is just a function passed as an argument to another function, usually to run later (often after an async operation like reading a file, fetching data, etc.).
function getData(callback) {
setTimeout(() => {
callback("Here is your data!");
}, 1000); // simulate 1s delay
}
getData((result) => {
console.log(result); // runs after 1s
});
Problem: When you need multiple async steps, you end up with callback hell:
getData((result) => {
console.log(result);
getData((result2) => {
console.log(result2);
getData((result3) => {
console.log(result3);
// ... and so on
});
});
});
Promises
A Promise is an object that represents the eventual result of an async operation. It has two states: fulfilled (success) or rejected (error).
let start = performance.now();
let data = fetch("https://microsoftedge.github.io/Demos/json-dummy-data/1MB.json").then(response => response.json()).catch(err => {
console.log("Error: " + err);
}).finally(() => {
console.log("Finished Processing. " + (performance.now() - start));
});
const response = await data;
console.log(Object.keys(response).length);